﻿#include"compile.h"
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include"vmdef.h"
#include"symboltable.h"
SymbolTable s_table;//符号表
QCompVMClist vmc_list;
//#include"msave.c"
int nowTokid = 0;
static QCompErr makeErr(int row, int line, char* info)
{
	QCompErr er;
	er.line = line;
	er.row = row;
	er.info = info;
	return er;
}
static QCompErr makeCurErr(char* info)
{
	return makeErr(cur_token.row, cur_token.line, info);
}

static void throw_err(QCompErr err)
{
	printf("at: row:%d,line:%d\n    %s\n", err.row, err.line, err.info);
	exit(-1);
}
static bool test_print_vmcfile(char* path)
{
	FILE* fp;
	if ((fp = fopen(path, "rb")) == NULL)
		return false;
	char* buf = "";
	int s1, s2, s3 = -1;
	while (true)
	{
		fread(&s1, sizeof(int), 1, fp);
		printf("op:%d,", s1);
		fread(&s1, sizeof(int), 1, fp);
		printf("lvals:%d,", s1);
		fread(&s2, sizeof(int), 1, fp);
		printf("rvals:%d,", s2);
		fread(&buf, s1, 1, fp);
		printf("lval:%s,", buf);
		fread(&buf, s2, 1, fp);
		printf("rval:%s\n", buf);
		if (feof(fp))
			break;
	}
	fclose(fp);
	return true;
	return true;
}
typedef struct
{
	int lval;
	char op[2];
	int rval;
}QNodes;
static bool initVmcList()
{
	vmc_list.cur_id = 0;
	return true;
}
static void addVmCode(QCompVMC vmc)
{
	vmc_list.vmclist[vmc_list.cur_id] = vmc;
	++vmc_list.cur_id;
}
MValue makeValue(void* val, int type)
{
	MValue r = MCreateValue(1);
	MSetValue(val, &r);
	r.type = type;
	return r;
}
static QCompVMC makeVMC(int op, MValue lval)
{
	QCompVMC re;
	re.op_vmc = op;
	re.val = lval;
	return re;
}
static QNodes makeNodes(int lval, char* op, int rval)
{
	QNodes nod = { 0 };
	nod.lval = lval;
	nod.rval = rval;
	strcpy(nod.op, op);
	return nod;
}
static bool nextToken()
{
	if (nowTokid == token_list->cur)
		return false;
	cur_token = token_list->tlist[nowTokid];
	nowTokid++;
	return true;
}
static QToken lookNext()
{
	if (nowTokid == token_list->cur)
		throw_err(makeCurErr("No match words but ended."));
	return token_list->tlist[nowTokid];
}
void QInitCompile(QTokenList* tl)
{
	if (!InitSymbolTable(&s_table, 1024))
		throw_err(makeCurErr("Cannot init the symboltable!"));
	token_list = tl;
}


static void expr_mainexpr();
static void expr_equal();
static void expr_keywordterm();
static void expr_define();
//
static void calc_factor();
static void calc_term();
static void calc_expr();
static void calc_calc(char* sym);
//expr-> term(+/-)term *
//term-> factor(*//)factor *
//factor-> NUM
//		-> LP/RP
//		-> +/-
static void calc_expr()
{
	calc_term();
	while (strcmp(cur_token.value, "+") == 0 || strcmp(cur_token.value, "-") == 0)
	{
		char* sy = cur_token.value;
		if (nextToken())
		{
			calc_term();
			calc_calc(sy);
			addVmCode(makeVMC(VMC_PUSHV, makeValue(NULL, VTYPE_INT), makeValue(NULL, VTYPE_INT)));
		}
		else
		{
			throw_err(makeCurErr("COM:there is nothing behind '+' or '-'!"));
		}
	}
	//addVmCode(makeVMC(VMC_MOV, "ax", "cx"));
}
static void calc_calc(char* sym)
{
	if (strcmp(sym, "+") == 0)
		addVmCode(makeVMC(VMC_ADD, makeValue(NULL, VTYPE_INT)));
	else if (strcmp(sym, "-") == 0)
		addVmCode(makeVMC(VMC_SUB, makeValue(NULL, VTYPE_INT)));
	else if (strcmp(sym, "*") == 0)
		addVmCode(makeVMC(VMC_MUL, makeValue(NULL, VTYPE_INT)));
	else if (strcmp(sym, "/") == 0)
		addVmCode(makeVMC(VMC_DIV, makeValue(NULL, VTYPE_INT)));
	else
	{
		throw_err(makeCurErr("COM:no such a operation to calc!"));
	}
}
static void calc_term()
{
	calc_factor();
	while (strcmp(cur_token.value, "*") == 0 || strcmp(cur_token.value, "/") == 0)
	{
		char* sy = cur_token.value;
		if (nextToken())
		{
			calc_factor();
			calc_calc(sy);
			addVmCode(makeVMC(VMC_PUSHV, makeValue(NULL, VTYPE_INT), makeValue(NULL, VTYPE_INT)));
		}
		else
		{
			throw_err(makeCurErr("COM:there is nothing behind '*' or '/'!"));
		}
	}
	//addVmCode(makeVMC(VMC_MOV, "ax", "cx"));

}
static void calc_getvalue()
{
	if (cur_token.type == TT_WORD)
	{
		//是一个变量
		SymbolInf sym = SearchSymbol(&s_table, cur_token.value);
		if (sym.used == false)
			throw_err(makeCurErr("COM:variable undefined !"));
		addVmCode(makeVMC(VMC_PUSH, makeValue(0, VTYPE_NULL)));
		addVmCode(makeVMC(VMC_STG, makeValue(sym.value, VTYPE_INT)));//加入指令，根据变量偏移值计算变量地址存在栈中的地址
		addVmCode(makeVMC(VMC_PUSHV, makeValue(NULL, VTYPE_INT)));
		addVmCode(makeVMC(VMC_VLL, makeValue(NULL, VTYPE_INT)));
		//VLL指令后不会直接入栈
		addVmCode(makeVMC(VMC_PUSHV, makeValue(NULL, VTYPE_INT)));
	}
	else if (cur_token.type == TT_NUM)
	{
		addVmCode(makeVMC(VMC_PUSH, makeValue(atoi(cur_token.value), VTYPE_INT)));
	}
	else if (cur_token.type == TT_SYMBOL)
	{
		if (strcmp(cur_token.value, "+") == 0)
		{
			nextToken();
			addVmCode(makeVMC(VMC_PUSH, makeValue(atoi(cur_token.value), VTYPE_INT)));
		}
		else if (strcmp(cur_token.value, "-") == 0)
		{
			nextToken();
			addVmCode(makeVMC(VMC_PUSH, makeValue(0 - atoi(cur_token.value), VTYPE_INT)));
		}
	}
	else if (strcmp(cur_token.value, "(") == 0 || strcmp(cur_token.value, ")") == 0)
	{
		nextToken();
		calc_expr();
	}
	else throw_err(makeCurErr("COM: fail to load value! not a variable or a number!"));
	nextToken();
}
static void calc_factor()
{
	int re;
	calc_getvalue();
}
static void expr_mainexpr()
{
	nextToken();
	while (true)
	{
		expr_equal();
		if (nowTokid == token_list->cur)
			break;
	}
	int a = 0;
}
static void expr_equal()
{
	//表达式
	//equal-> defineterm|value '=' calc
	expr_define();//检查定义变量
	if (cur_token.type != TT_WORD)
		throw_err(makeCurErr("The left value of the expr must be a variable or an define expr!\nBut not an const number or an operation code!"));
	SymbolInf sym = SearchSymbol(&s_table, cur_token.value);//先查找有没有左值变量
	if (sym.used == false)
		throw_err(makeCurErr("Cannot find such a variable!"));
	if (!nextToken())
		throw_err(makeCurErr("The right value of the '=' must be a expr!"));
	if (strcmp(cur_token.value, "=") == 0)
	{
		//有等号
		if (!nextToken())
			throw_err(makeCurErr("The right value of the '=' must be a expr!"));
		calc_expr();//计算值
		addVmCode(makeVMC(VMC_STG, makeValue(sym.value, VTYPE_INT)));//加入指令，根据变量偏移值计算变量地址存在栈中的地址
		addVmCode(makeVMC(VMC_PUSHV, makeValue(NULL, VTYPE_INT)));
		//先入欲赋的值，在入地址
		addVmCode(makeVMC(VMC_VLL, makeValue(NULL, VTYPE_INT)));//加载变量
	}
	else throw_err(makeCurErr("No matched symbol '='!"));
}
static void expr_keywordterm()
{

}
static void expr_define()
{
	if (strcmp(cur_token.value, "var") == 0)
	{
		//首先是var声明语句
		QToken tok = lookNext();
		//向前获取一个token(此处不用nexttoken因为如果var a=1,这种情况后面会跟一个=号来赋值变量。
		if (SearchSymbol(&s_table, tok.value).used == true)
		{
			throw_err(makeCurErr("Redefine a variable !"));
		}
		//如果符号表中存有该变量，则报错
		AddSymbol(&s_table, MakeSymbolInf(tok.value, VTYPE_NULL, s_table.cur));//按照偏移值填写
		tok = token_list->tlist[nowTokid + 1];
		int n = 1;
		if (strcmp(tok.value, "as") == 0)
		{
			//是否声明语句后接一个as来定义变量类型
			tok = token_list->tlist[nowTokid + 2];
			if (strcmp(tok.value, "Int") == 0)
			{
				//判断系统默认类型
				SetSymbolType(&s_table, s_table.cur - 1, VTYPE_INT);
			}
			else if (strcmp(tok.value, "String") == 0)
			{
				//判断系统默认类型
				SetSymbolType(&s_table, s_table.cur - 1, VTYPE_STR);
			}
			else if (strcmp(tok.value, "Bool") == 0)
			{
				SetSymbolType(&s_table, s_table.cur - 1, VTYPE_INT);
			}
			else
			{
				throw_err(makeCurErr("No match variable type,it's not a system variable or a table!"));
			}
			nextToken();
			nextToken();
			nextToken();
			//将token位后移
		}
		int cn = s_table.cur_sta;//记录变量起始栈
		SetSymbolValue(&s_table, s_table.cur - 1, s_table.cur_sta);
		s_table.cur_sta += n;
		for (int i = cn; i < cn + n; i++)
		{
			//依次为所占用的栈分配相应内存地址，并设置栈的值为内存地址
			//由于可能分配n段地址（一个结构体）因此用for循环实现
			addVmCode(makeVMC(VMC_VLMALL, makeValue(NULL, VTYPE_INT)));//分配内存
			addVmCode(makeVMC(VMC_PUSHV, makeValue(NULL, VTYPE_INT)));
		}

	}
	nextToken();
}
QCompErr* QMakeCompile()
{
	if (!initVmcList())
		throw_err(makeErr(-1, -1, "cannot init the vm list!"));
	//nextToken();
	expr_mainexpr();
	printf("try to ouput the vmcode...\n");
	if (!QOutputVmc("t.qvc"))
	{
		throw_err(makeErr(-1, -1, "can not write out the vmcode at:t.qvc!"));
	}
	//test_print_vmcfile("t.qvc");
	return NULL;
}
static int QGetVmSize(int csize)
{
	if (csize == 0)
		return 0;
	else if (csize == 1)
		return VMS_CHAR;
	else if (csize == 2)
		return VMS_SHORT;
	else if (csize > 2 && csize <= 4)
		return VMS_INT;
	else if (csize > 4 && csize <= 8)
		return VMS_LONG;
	else return VMS_TOP;
}
bool QOutputVmc(char* path)
{
	FILE* fp;
	if ((fp = fopen(path, "wb")) == NULL)
		return false;
	for (size_t i = 0; i < vmc_list.cur_id; i++)
	{
		//遍历所有字节码
		fwrite(&vmc_list.vmclist[i], sizeof(QCompVMC), 1, fp);
	}
	fclose(fp);
	return true;
}
